﻿using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;

public class FileSecurityManager
{
    // 常量定义
    private const uint DACL_SECURITY_INFORMATION = 0x00000004;
    private const uint PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000;
    private const uint SE_FILE_OBJECT = 1;
    private const uint OWNER_SECURITY_INFORMATION = 0x00000001;
    private const uint SECURITY_DESCRIPTOR_REVISION = 1;

    // Win32 API 声明
    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool GetFileSecurity(
        string lpFileName,
        uint RequestedInformation,
        IntPtr pSecurityDescriptor,
        uint nLength,
        out uint lpnLengthNeeded);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool SetFileSecurity(
        string lpFileName,
        uint SecurityInformation,
        IntPtr pSecurityDescriptor);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool InitializeSecurityDescriptor(
        IntPtr pSecurityDescriptor,
        uint dwRevision);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool SetSecurityDescriptorDacl(
        IntPtr pSecurityDescriptor,
        bool bDaclPresent,
        IntPtr pDacl,
        bool bDaclDefaulted);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool SetNamedSecurityInfo(
        string pObjectName,
        uint ObjectType,
        uint SecurityInfo,
        IntPtr psidOwner,
        IntPtr psidGroup,
        IntPtr pDacl,
        IntPtr pSacl);

    [DllImport("kernel32.dll")]
    private static extern void ZeroMemory(IntPtr dest, int size);

    /// <summary>
    /// 锁定文件权限，禁止添加或删除用户/组
    /// </summary>
    /// <param name="filePath">文件路径</param>
    public static void LockFilePermissions(string filePath)
    {
        if (!File.Exists(filePath))
            throw new FileNotFoundException("指定的文件不存在", filePath);

        // 1. 获取文件所有权
        TakeOwnership(filePath);

        // 2. 获取当前DACL
        IntPtr pOldDacl = GetFileDacl(filePath);

        try
        {
            // 3. 创建新的安全描述符
            IntPtr pSd = Marshal.AllocHGlobal(1024);
            ZeroMemory(pSd, 1024);

            try
            {
                if (!InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION))
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                // 4. 设置DACL并保护它不被修改
                if (!SetSecurityDescriptorDacl(pSd, true, pOldDacl, false))
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                // 5. 应用新的安全设置
                uint securityInfo = DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION;
                if (!SetFileSecurity(filePath, securityInfo, pSd))
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                Console.WriteLine("成功锁定文件权限，禁止添加或删除用户/组。");
            }
            finally
            {
                Marshal.FreeHGlobal(pSd);
            }
        }
        finally
        {
            if (pOldDacl != IntPtr.Zero)
                Marshal.FreeHGlobal(pOldDacl);
        }
    }

    /// <summary>
    /// 获取文件的DACL
    /// </summary>
    private static IntPtr GetFileDacl(string filePath)
    {
        uint lengthNeeded = 0;

        // 第一次调用获取所需缓冲区大小
        GetFileSecurity(filePath, DACL_SECURITY_INFORMATION, IntPtr.Zero, 0, out lengthNeeded);

        if (lengthNeeded == 0 && Marshal.GetLastWin32Error() != 0)
            throw new Win32Exception(Marshal.GetLastWin32Error());

        // 分配缓冲区
        IntPtr buffer = Marshal.AllocHGlobal((int)lengthNeeded);
        ZeroMemory(buffer, (int)lengthNeeded);

        // 第二次调用获取实际安全描述符
        if (!GetFileSecurity(filePath, DACL_SECURITY_INFORMATION, buffer, lengthNeeded, out lengthNeeded))
        {
            Marshal.FreeHGlobal(buffer);
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        return buffer;
    }

    /// <summary>
    /// 获取文件所有权
    /// </summary>
    private static void TakeOwnership(string filePath)
    {
        WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
        SecurityIdentifier userSid = currentUser.User;

        // 将SecurityIdentifier转换为二进制形式的SID
        byte[] sidBytes = new byte[userSid.BinaryLength];
        userSid.GetBinaryForm(sidBytes, 0);

        // 将字节数组复制到非托管内存
        IntPtr pUserSid = Marshal.AllocHGlobal(sidBytes.Length);
        try
        {
            Marshal.Copy(sidBytes, 0, pUserSid, sidBytes.Length);

            if (!SetNamedSecurityInfo(filePath, SE_FILE_OBJECT,
                OWNER_SECURITY_INFORMATION,
                pUserSid, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
        finally
        {
            Marshal.FreeHGlobal(pUserSid);
        }
    }
}